#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/msg.h>
#include <errno.h>
#include "MQTTClient.h"
#include "cJSON.h"  // 使用您提供的cJSON库

#define ADDRESS     "mqtt.yyzlab.com.cn"
#define CLIENTID    "ExampleClientSub"
#define TOPIC       "3498854532/AIOTSIM2Device"
#define QOS         1
#define TIMEOUT     10000L
#define MSG_QUEUE_KEY 12345  // 消息队列的键值

// 消息队列格式
typedef struct message
{
    long mtype;         // 消息类型
    char mtext[256];    // 消息内容
} Message;

int msgid;  // 消息队列ID
volatile MQTTClient_deliveryToken deliveredtoken;

// 初始化消息队列
void init_queue() {
    // 创建消息队列，不存在则创建，权限为0666
    msgid = msgget(MSG_QUEUE_KEY, 0666 | IPC_CREAT);
    if (msgid == -1) {
        perror("msgget failed");
        exit(EXIT_FAILURE);
    }
    printf("消息队列初始化成功，ID: %d\n", msgid);
}

// 销毁消息队列
void destroy_queue() {
    // 删除消息队列
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
        perror("msgctl failed");
        exit(EXIT_FAILURE);
    }
    printf("消息队列已销毁\n");
}

// 入队操作
void enqueue(const char *data) {
    Message msg;
    msg.mtype = 1;  // 设置消息类型为1
    
    // 复制数据到消息缓冲区，确保不溢出
    strncpy(msg.mtext, data, sizeof(msg.mtext) - 1);
    msg.mtext[sizeof(msg.mtext) - 1] = '\0';  // 确保字符串结束符
    
    // 发送消息到队列
    if (msgsnd(msgid, &msg, sizeof(msg.mtext), 0) == -1) {
        perror("msgsnd failed");
    } else {
        printf("消息已加入队列: %s\n", msg.mtext);
    }
}

// JSON转命令字符串 - 严格检查值类型（适配提供的cJSON库）
const char* json_to_command(cJSON *json_root) {
    if (json_root == NULL) return "INVALID_JSON";
    
    // 检查风扇状态 (布尔类型)
    cJSON *fan = cJSON_GetObjectItem(json_root, "fan");
    if (fan != NULL) {
        // 根据cJSON库定义，true是cJSON_True，false是cJSON_False
        if (fan->type == cJSON_True || fan->type == cJSON_False) {
            return (fan->type == cJSON_True) ? "FAN_ON" : "FAN_OFF";
        } else {
            return "INVALID_FAN_VALUE";
        }
    }
    
    // 检查灯光状态 (布尔类型)
    cJSON *lamp = cJSON_GetObjectItem(json_root, "lamp");
    if (lamp != NULL) {
        if (lamp->type == cJSON_True || lamp->type == cJSON_False) {
            return (lamp->type == cJSON_True) ? "LD1_ON" : "LD1_OFF";
        } else {
            return "INVALID_LAMP_VALUE";
        }
    }
    
    // 检查警报状态 (布尔类型)
    cJSON *alarm = cJSON_GetObjectItem(json_root, "alarm");
    if (alarm != NULL) {
        if (alarm->type == cJSON_True || alarm->type == cJSON_False) {
            return (alarm->type == cJSON_True) ? "BEEP_ON" : "BEEP_OFF";
        } else {
            return "INVALID_ALARM_VALUE";
        }
    }
    
    // 检查遮阳棚状态 (字符串类型)
    cJSON *sunshade = cJSON_GetObjectItem(json_root, "sunshade");
    if (sunshade != NULL) {
        if (sunshade->type == cJSON_String && sunshade->valuestring != NULL) {
            if (strcmp(sunshade->valuestring, "forward") == 0) {
                return "LD3_OFF";
            } else if (strcmp(sunshade->valuestring, "reverse") == 0) {
                return "LD3_ON";
            } else {
                return "INVALID_SUNSHADE_VALUE";
            }
        } else {
            return "SUNSHADE_NOT_STRING";
        }
    }
    
    return "UNKNOWN_COMMAND";
}

// 消息传递确认回调函数
void delivered(void *context, MQTTClient_deliveryToken dt)
{
    printf("Message with token value %d delivery confirmed\n", dt);
    deliveredtoken = dt;
}

// 消息到达回调函数 - 解析JSON并转换为命令后加入队列
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    printf("Message arrived\n");
    printf("     topic: %s\n", topicName);
    printf("   message: ");
    
    // 打印原始消息内容
    int i;
    char* payloadptr = message->payload;
    for(i=0; i<message->payloadlen; i++) {
        putchar(*payloadptr++);
    }
    putchar('\n');
    
    // 解析JSON（使用基础的cJSON_Parse，适配提供的库）
    payloadptr = message->payload;
    // 确保 payload 以 null 结尾
    char *payload_copy = malloc(message->payloadlen + 1);
    if (payload_copy) {
        memcpy(payload_copy, payloadptr, message->payloadlen);
        payload_copy[message->payloadlen] = '\0';
        
        cJSON *json_root = cJSON_Parse(payload_copy);
        const char *command = json_to_command(json_root);
        
        // 释放JSON对象
        if (json_root != NULL) {
            cJSON_Delete(json_root);
        }
        
        // 将转换后的命令加入队列
        printf("转换后的命令: %s\n", command);
        enqueue(command);
        
        free(payload_copy);
    } else {
        printf("内存分配失败，无法处理消息\n");
        enqueue("MEMORY_ERROR");
    }

    // 释放消息和主题名称占用的内存
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

// 连接丢失回调函数
void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("     cause: %s\n", cause);
}

int main(int argc, char* argv[])
{
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    int rc;
    char ch;

    // 初始化消息队列
    init_queue();

    // 创建MQTT客户端实例
    MQTTClient_create(&client, ADDRESS, CLIENTID,
        MQTTCLIENT_PERSISTENCE_NONE, NULL);
    
    // 配置连接选项
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    // 设置回调函数
    MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);

    // 连接到MQTT代理服务器
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        destroy_queue();
        exit(EXIT_FAILURE);
    }
    printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
           "Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);

    // 订阅主题
    MQTTClient_subscribe(client, TOPIC, QOS);

    // 等待用户输入Q或q退出
    do 
    {
        ch = getchar();
    } while(ch!='Q' && ch != 'q');

    // 清理资源
    MQTTClient_unsubscribe(client, TOPIC);
    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    
    // 销毁消息队列
    destroy_queue();
    
    return rc;
}
    